Load libraries

root_path <- "~/Desktop/raw_data_must/"
chrom_path <- paste0(root_path, "Chromium/")
vis_path <- paste0(root_path, "Visium/outs/")
xe_path <- paste0(root_path, "Xenium/outs/")
aggxe_path <- paste0(root_path, "AggXe/outs/")

suppressMessages({
  library(Seurat)
  library(BayesSpace)
  library(ggplot2)
  library(patchwork)
  library(dplyr)
  library(tibble)
  library(scater)
  library(scran)
  library(scuttle)
  library(grid)
  library(hrbrthemes)
  library(gridExtra)
  library(SingleR)
  library(magick)
  library(harmony)
  library(scales)
  library(knitr)
  library(here)
  library(cowplot)
})

source("utils_new.R")

Xenium Integration with Visium

Image Alignment

Visualize and rotate Visium and Xenium

First, we check the similarity between Visium and Xenium images. Visium comes with a H&E image.

Then we visualize the Xenium image. It can be obtained by taking a screenshot of the .ome.tif object in Xenium raw data, which was read in using a Java software Fiji. Note that after some scaling and rotation, Xenium can be aligned to Visium. In image processing, such transformation can be done by multiplying the source image with a linear affine transformation matrix, to map it onto the same scale as the target image.

ggdraw() + 
  draw_image("www/tissue_lowres_image.png", width = 0.55) + 
  draw_label ("Visium H&E", hjust = 0, vjust = 0, x = 0, y = 0.95) + 
  draw_image("www/img_xe_rotate_scale.png", width = 0.25, x = 0.7) + 
  draw_label ("Xenium .ome.tif (rotate & shrink)", hjust = 0, vjust = 0, x = 0.6, y = 0.95)

Various image registration methods

There are many ways of image registration in R, Python, with other plug-ins.

  • SpatialData is a Python package that requires user-selected landmarks to align images. Here shows the registration of Visium onto Xenium in SpatialData’s napari interface (Marconato et al. 2023).


  • R packages RNiftyReg can be combined with mmand for automated image registration. After alignment, we will obtain the registered images with a transformation matrix. Here is a demonstration with external data, before and after registration of two slices (Clayden 2015).

           However, the automation does not work well on images with very different orientation, scale, and intensity,
           such as in this use-case of Xenium and Visium.


  • Therefore, we use the transformation matrix provided by 10x, which was done by registration with Python and a Java plug-in Fiji. The following matrix is the result of registering Xenium onto Visium.

    # Affine matrix aligned by 10X
    trans_mtx <- matrix(
      c(
        8.82797498e-02, -1.91831377e+00,  1.63476055e+04,
        1.84141210e+00,  5.96797885e-02,  4.12499099e+03,
        -3.95225478e-07, -4.66405945e-06,  1.03706895e+00
      ),
      nrow = 3, byrow= TRUE
    )
    trans_mtx

Aggregate Xenium into circles as Visium

We have developed a Bioconductor R package for binning any single-cell resolution spatial data into spots, which can be useful in checking correlations between technical replicates of the same technology, identify artifacts across technologies, and checking cell density (number of cells per spot). The user can choose to bin from transcript-level (sub-cellular) or cell-level. Our package bin2spot will soon be available to the public after some optimization with the speed in the backend.

# aggxe <- bin2spot::aggregate_xenium(xe, scaling_factor)

For this tutorial, we have saved the output of the binned Xenium object, aggregated by our lab member.

Here is the result of post affine transformation and aggregation, the aligment of Xenium onto Visium.

References

Clayden, Jon. 2015. Image Processing and Alignment with RNiftyReg and Mmand. Aalborg, Denmark: useR! 2015. https://user2015.math.aau.dk/presentations/46.pdf.
Marconato, Luca, Giovanni Palla, Kevin A Yamauchi, Isaac Virshup, Elyas Heidari, Tim Treis, Marcella Toth, et al. 2023. “SpatialData: An Open and Universal Data Framework for Spatial Omics.” bioRxiv, 2023–05.